package main

import "fmt"

func main() {
	/*
		OOP中的继承性：
			如果两个类（class）存在继承关系，其中一个是子类，另一个作为父类，那么：

			1.子类可以直接访问父类的属性和方法
			2.子类可以新增自己的属性和方法
			3.子类可以重写父类的方法（orverride，就是将父类已有的的方法，重新实现）

		Go语言的结构体嵌套：
			1.模拟继承性：is - a
				type A struct {
					field
				}
				type B struct {
					A //匿名字段
				}
			（1）访问时，z.Y.X.a 可以简化为 z.Y.a 或 z.a
				此时，如果外层字段和内层字段有相同的方法，则使用简化模式访问外层的方法会覆盖内层的方法，
				Go编译器优先从外向内逐层查找方法（类似于“子类覆盖父类的方法”）
			（2）无论是类型变量还是指针变量，都可以调用类型的所有方法

					T：接收者的值类型   			*T：接收者的指针类型
					S：接收者是值类型的方法集 		*S：接收者是指针类型的方法集
				  但是通过类型字面量显式地进行值调用和表达式调用时：
					T 只能调用 S
					*T 能调用 S 和 *S

			2.模拟聚合关系：has - a
				type C struct {
					field
				}
				type D struct {
					c C //聚合关系
				}
	*/
	//1.创建Person3类型
	p1 := Person3{"灰太狼", 36}
	fmt.Println(p1.name, p1.age) //父类对象，访问父类的字段属性
	p1.eat()                     //父类对象，访问父类方法

	//2.创建Student3类型
	s1 := Student3{Person3: Person3{"喜羊羊", 18}, school: "大肥羊学校"}
	fmt.Println(s1.name)   //s1.Person3.name
	fmt.Println(s1.age)    //子类对象，可以直接访问父类的字段,(其实就是提升字段)
	fmt.Println(s1.school) //子类对象，访问自己新增的字段属性

	s1.eat()         //子类对象，访问父类的方法
	s1.study()       //子类对象，访问子类新增的方法
	s1.eat()         //如果存在方法的重写，子类对象访问重写的方法
	s1.Person3.eat() //如果方法重写后，也可以这样来调用父类的方法

	fmt.Println("----------------------类型字面量显示调用-------------------------")
	fmt.Println("------1.第一种显示调用的方法------")
	(Student3).sleep(s1)
	//(Student3).eat(s1) //Student3 无法调用 *Person3 的方法集
	(*Student3).sleep(&Student3{Person3: Person3{name: "灰太狼", age: 36}, school: "狼族教育贵族学校"})
	(*Student3).eat(&s1)

	fmt.Println("------2.第二种显示调用的方法------")
	(Student3)(s1).sleep()
	//(Student3)(Student3{Person3: Person3{name: "灰太狼", age: 36}, school: "狼族教育贵族学校"}).eat() //Student3 无法调用 *Person3 的方法集
	(*Student3)(&s1).eat()
	(*Student3)(&Student3{Person3: Person3{name: "灰太狼", age: 36}, school: "狼族教育贵族学校"}).sleep()
}

// 1.定义一个”父类“
type Person3 struct {
	name string
	age  int
}

// 2.定义一个“子类”
type Student3 struct {
	Person3 //结构体嵌套，模拟继承性
	school  string
}

// 3.方法
func (p *Person3) eat() {
	fmt.Println("父类的方法，*Person3。。。")
}

func (p Person3) sleep() {
	fmt.Println("父类的方法，Person3。。。")
}

func (s Student3) study() {
	fmt.Println("子类新增的方法，学生学习啦。。。")
}

//func (s Student3) eat() {
//	fmt.Println("子类重写的方法，学生吃书。。。")
//}
